#include "coursefactory.h"

/// The one-and-only CourseFactory instance.
CourseFactory* CourseFactory::instance_;

/// pimpl definition.
struct CourseFactoryImpl {
	CourseFactory::pool_type course_pool_;
};

CourseFactory::CourseFactory() : pimpl_(new CourseFactoryImpl)
{
}

CourseFactory::~CourseFactory()
{
    delete instance_;
}

/// Gain access to the one-and-only CourseFactory instance.
/// \return The one-and-only CourseFactory instance.
CourseFactory* CourseFactory::instance()
{
    if( instance_ == 0 )
        instance_ = new CourseFactory();
    return instance_;
}

/// Helper function which merely returns a reference to the flyweights pool.
/// \return The course pool.
CourseFactory::pool_type& CourseFactory::flyweights() const
{
	return pimpl_->course_pool_;
}

/// Access the one instance of a Course object specified by the Course id.
/// \param id The Course object id.
/// \return The one and only instance of the Course object.
boost::shared_ptr<Course> CourseFactory::get(const std::string& id)
{
	return get(Course(id));
}

/// Access the one instance of a Course object.  This function is mostly used
/// for adding new flyweights to the factory.
/// \param id The Course object to get.
/// \return The one and only instance of the Course object.
boost::shared_ptr<Course> CourseFactory::get(const Course& course)
{
	std::string id = course.getCourseID();
	pool_type::iterator position = flyweights().find(id);
	if( position == flyweights().end() ) {
		boost::shared_ptr<Course> new_course(new Course(course));
		flyweights().insert(pool_pair(id, new_course));
		return new_course;
	}
	return (*position).second;
}

/// Access the flyweights pool through start- and end-iterators.
/// \return A pair of iterators, the first of which points to the beginning of
/// the flyweights pool and the second of which points to the end.
CourseFactory::pool_range CourseFactory::pool() const
{
	return pool_range(flyweights().begin(), flyweights().end());
}
